// 客户端
#include <iostream>
#include <string>
#include <cstdint>
#include <string.h>

#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/types.h>
#include "Thread.hpp"

using namespace ThreadModule; // 引入线程模块

// 文件描述符设置为 0,设置为全局
int sockfd = 0;

// 把ip 和 端口号   都定义成为全局
std::string server_ip;
uint16_t server_port = 0; // 当前的端口号IP
pthread_t id;    //定义一个全局id

//如果为多线程，编译文件，编译的时候要带上 -lpthread
//receiver 读
void Recv()
{
    //只需要不断地定义buffer 从文件描述符中把内容读出来，并打印出来
    while (true)
    {
        char buffer[1024];
        struct sockaddr_in peer;
        socklen_t len = sizeof(peer);
        // 要知晓对应的服务端   末尾两个参数（参数不能省略）  和server内容一致
        // 收消息可能是多个服务端的消息，可以打印出来
        int m = recvfrom(sockfd, buffer, sizeof(buffer) - 1, 0, (struct sockaddr *)&peer, &len);
        (void)m;
        // 读取成功
        if (m > 0)
        {
            buffer[m] = 0;
            std::cerr << buffer << std::endl;     //往标准错误里打 2
        }
    }
}


// 发送方 （sender线程一直要做的就是发消息）
void Send()
{
    // 填写服务器信息（只有发送方才关注服务端信息）
    struct sockaddr_in server;
    memset(&server, 0, sizeof(server));
    server.sin_family = AF_INET; // 网络家族
    server.sin_port = htons(server_port);
    server.sin_addr.s_addr = inet_addr(server_ip.c_str());

    const std::string online = "inline";
    sendto(sockfd,online.c_str(),online.size(),0,(struct sockaddr*)&server,sizeof(server));


    // sender 线程要做的就是要一直发消息（不断从标准输入获取）
    while (true)
    {
        std::string input;
        std::cout << "Please Enter# ";   //输出往1里面打
        std::getline(std::cin, input);   //输入往0里打

        // 消息发送（并发送消息  sendto）
        int n = sendto(sockfd, input.c_str(), input.size(), 0, (struct sockaddr *)&server, sizeof(server));
        (void)n;

        if(input == "QUIT")
        {
            pthread_cancel(id);   //直接关闭线程，当一个用户退出，要让别人也知晓这个用户退出
            break;
        }
    }
}

// 对于客户端   也需要做多线程改造（单线程会导致先发消息，再读消息    会导致内容阻塞，就需要多线程，一个发消息，一个读消息）
int main(int argc, char *argv[])
{
    if (argc != 3)
    {
        std::cerr << "Usage: " << argv[0] << " server_ip server_port" << std::endl;
        return 1;
    }//cerr 对应的是2

    // 不再需要重新定义，直接赋值
    server_ip = argv[1];
    server_port = std::stoi(argv[2]);

    // 1.创建套接字（直接赋值给全局sockfd）
    sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    // 套接字小于0    创建失败
    if (sockfd < 0)
    {
        std::cout << "socket error" << std::endl;
        return 2;
    }

    // 创建线程(参数1：sockfd)
    Thread receiver(Recv); // 收线程  读   
    Thread sender(Send);   // 发线程  写

    receiver.Start(); // 线程启动
    sender.Start();

    //拿取线程
    id = receiver.Id();

    receiver.Join();
    sender.Join();

    return 0;
}